package video.conference;
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */




import java.io.*;
import java.net.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;

public class ServerVideo extends JFrame implements ActionListener {

	//RTP variables:
	//----------------
	DatagramSocket RTPsocket; //socket to be used to send and receive UDP packets
	DatagramPacket senddp; //UDP packet containing the video frames

	InetAddress ClientIPAddr; //Client IP address
	int RTP_dest_port = 0; //destination port for RTP packets  (given by the RTSP Client)

	//GUI:
	//----------------
	JLabel label;

	//Video variables:
	//----------------
	int imagenb = 0; //image nb of the image currently transmitted
	VideoStream video; //VideoStream object used to access video frames
	static int MJPEG_TYPE = 26; //RTP payload type for MJPEG video
	static int FRAME_PERIOD = 100; //Frame period of the video to stream, in ms
	static int VIDEO_LENGTH = 500; //length of the video in frames

	Timer timer; //timer used to send the images at the video frame rate
	byte[] buf; //buffer used to store the images to send to the client

	//RTSP variables
	//----------------
	//rtsp states
	final static int INIT = 0;
	final static int READY = 1;
	final static int PLAYING = 2;
	//rtsp message types
	final static int SETUP = 3;
	final static int PLAY = 4;
	final static int PAUSE = 5;
	final static int TEARDOWN = 6;

	static int state; //RTSP Server state == INIT or READY or PLAY
	Socket RTSPsocket; //socket used to send/receive RTSP messages
	//input and output stream filters
	static BufferedReader RTSPBufferedReader;
	static BufferedWriter RTSPBufferedWriter;
	static String VideoFileName; //video file requested from the client
	static int RTSP_ID = 123456; //ID of the RTSP session
	int RTSPSeqNb = 0; //Sequence number of RTSP messages within the session

	final static String CRLF = "\r\n";
	private static int rtspPortUsed;

	//--------------------------------
	//Constructor
	//--------------------------------
	public ServerVideo(){

		//init Frame
		super("Server");

		//init Timer
		timer = new Timer(FRAME_PERIOD, this);
		timer.setInitialDelay(0);
		timer.setCoalesce(true);

		//allocate memory for the sending buffer
		buf = new byte[15000];

		//Handler to close the main window
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				//stop the timer and exit
				timer.stop();
				System.exit(0);
			}});

		//GUI:
		label = new JLabel("Send frame #        ", JLabel.CENTER);
		getContentPane().add(label, BorderLayout.CENTER);
	}
	
	public static int getRtspPortUsed() {
		return rtspPortUsed;
	}

	//------------------------------------
	//main
	//------------------------------------
	public static void main(String argv[]) throws Exception
	{
		int RTSPport = Integer.parseInt(argv[0]);
		mainMethod(RTSPport);
	}

	public static int mainMethod(int RTSPport) throws IOException, Exception,
	SocketException {
		File file = new File("movie.Mjpeg");
		//	  System.out.println(file.getAbsolutePath()+" exists "+file.exists());
		//create a Server object
		final ServerVideo theServer = new ServerVideo();

		//show GUI:
		theServer.pack();
		theServer.setVisible(true);

		//Initiate TCP connection with the client for the RTSP session
		final ServerSocket listenSocket = new ServerSocket(RTSPport);
		rtspPortUsed = listenSocket.getLocalPort();
		new Thread(){
			public void run() {

				try{
					theServer.RTSPsocket = listenSocket.accept();
					listenSocket.close();

					//Get Client IP address
					theServer.ClientIPAddr = theServer.RTSPsocket.getInetAddress();

					//Initiate RTSPstate
					state = INIT;

					//Set input and output stream filters:
					RTSPBufferedReader = new BufferedReader(new InputStreamReader(theServer.RTSPsocket.getInputStream()) );
					RTSPBufferedWriter = new BufferedWriter(new OutputStreamWriter(theServer.RTSPsocket.getOutputStream()) );

					//Wait for the SETUP message from the client
					int request_type;
					boolean done = false;
					while(!done)
					{
						request_type = theServer.parse_RTSP_request(); //blocking

						if (request_type == SETUP)
						{ 
							done = true;

							//update RTSP state
							state = READY;
							System.out.println("New RTSP state: READY");

							//Send response
							theServer.send_RTSP_response();

							//init the VideoStream object:
							theServer.video = new VideoStream(VideoFileName);

							//init RTP socket
							theServer.RTPsocket = new DatagramSocket();
						}
					}

					//loop to handle RTSP requests
					while(true)
					{
						//parse the request
						request_type = theServer.parse_RTSP_request(); //blocking

						if ((request_type == PLAY) && (state == READY))
						{
							//send back response
							theServer.send_RTSP_response();
							//start timer
							theServer.timer.start();
							//update state
							state = PLAYING;
							System.out.println("New RTSP state: PLAYING");
						}
						else if ((request_type == PAUSE) && (state == PLAYING))
						{
							//send back response
							theServer.send_RTSP_response();
							//stop timer
							theServer.timer.stop();
							//update state
							state = READY;
							System.out.println("New RTSP state: READY");
						}
						else if (request_type == TEARDOWN)
						{
							//send back response
							theServer.send_RTSP_response();
							//stop timer
							theServer.timer.stop();
							//close sockets
							theServer.RTSPsocket.close();
							theServer.RTPsocket.close();

							System.exit(0);
						}
					}
				}catch(Exception e){
					e.printStackTrace();
				}
			};
		}.start();
		return rtspPortUsed;
	}


	//------------------------
	//Handler for timer
	//------------------------
	public void actionPerformed(ActionEvent e) {

		//if the current image nb is less than the length of the video
		if (imagenb < VIDEO_LENGTH)
		{
			//update current imagenb
			imagenb++;

			try {
				//get next frame to send from the video, as well as its size
				int image_length = video.getnextframe(buf);

				//Builds an RTPpacket object containing the frame
				RTPpacket rtp_packet = new RTPpacket(MJPEG_TYPE, imagenb, imagenb*FRAME_PERIOD, buf, image_length);

				//get to total length of the full rtp packet to send
				int packet_length = rtp_packet.getlength();

				//retrieve the packet bitstream and store it in an array of bytes
				byte[] packet_bits = new byte[packet_length];
				rtp_packet.getpacket(packet_bits);

				//send the packet as a DatagramPacket over the UDP socket
				senddp = new DatagramPacket(packet_bits, packet_length, ClientIPAddr, RTP_dest_port);
				RTPsocket.send(senddp);

				//System.out.println("Send frame #"+imagenb);
				//print the header bitstream
				rtp_packet.printheader();

				//update GUI
				label.setText("Send frame #" + imagenb);
			}
			catch(Exception ex)
			{
				System.out.println("Exception caught: "+ex); ex.printStackTrace();
				System.exit(0);
			}
		}
		else
		{
			//if we have reached the end of the video file, stop the timer
			timer.stop();
		}
	}

	//------------------------------------
	//Parse RTSP Request
	//------------------------------------
	private int parse_RTSP_request()
	{
		int request_type = -1;
		try{
			//parse request line and extract the request_type:
			String RequestLine = RTSPBufferedReader.readLine();
			System.out.println("RTSP Server - Received from Client:");
			System.out.println(RequestLine);

			StringTokenizer tokens = new StringTokenizer(RequestLine);
			String request_type_string = tokens.nextToken();
			System.out.println("request_string is: "+request_type_string);

			//convert to request_type structure:
			if ((new String(request_type_string)).compareTo("SETUP") == 0)
				request_type = SETUP;
			else if ((new String(request_type_string)).compareTo("PLAY") == 0)
				request_type = PLAY;
			else if ((new String(request_type_string)).compareTo("PAUSE") == 0)
				request_type = PAUSE;
			else if ((new String(request_type_string)).compareTo("TEARDOWN") == 0)
				request_type = TEARDOWN;

			if (request_type == SETUP)
			{
				//extract VideoFileName from RequestLine
				VideoFileName = tokens.nextToken();
				System.out.println("VideoFileName is: "+VideoFileName);
			}

			//parse the SeqNumLine and extract CSeq field
			String SeqNumLine = RTSPBufferedReader.readLine();
			System.out.println(SeqNumLine);
			tokens = new StringTokenizer(SeqNumLine);
			tokens.nextToken();
			RTSPSeqNb = Integer.parseInt(tokens.nextToken());
			System.out.println("RTSPSeqNb = "+ RTSPSeqNb);


			//get LastLine
			//      String LastLine = "bla";
			String LastLine = RTSPBufferedReader.readLine();
			System.out.println("Now showing Last Line: ");
			System.out.println(LastLine);

			if (request_type == SETUP)
			{
				//extract RTP_dest_port from LastLine
				tokens = new StringTokenizer(LastLine);
				for (int i=0; i<3; i++)
					tokens.nextToken(); //skip unused stuff
				RTP_dest_port = Integer.parseInt(tokens.nextToken());
			}
			//else LastLine will be the SessionId line ... do not check for now.
		}
		catch(Exception ex)
		{
			System.out.println("Exception caught: "+ex); ex.printStackTrace();
			System.exit(0);
		}
		return(request_type);
	}

	//------------------------------------
	//Send RTSP Response
	//------------------------------------
	private void send_RTSP_response()
	{
		try{
			RTSPBufferedWriter.write("RTSP/1.0 200 OK"+CRLF);
			RTSPBufferedWriter.write("CSeq: "+RTSPSeqNb+CRLF);
			RTSPBufferedWriter.write("Session: "+RTSP_ID+CRLF);
			RTSPBufferedWriter.flush();
			//System.out.println("RTSP Server - Sent response to Client.");
		}
		catch(Exception ex)
		{
			System.out.println("Exception caught: "+ex); ex.printStackTrace();
			System.exit(0);
		}
	}
}
